#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>

/*
{"type":"ugc","codecid":7,"groupId":"BV1qF411t72r","itemId":516644182,"aid":296817273,"cid":516644182,"bvid":"BV1qF411t72r","p":4,"tabP":0,"tabName":"4.图册与相
容性、微分同胚Diffeomorphism、标量场、闭集、连通性","uid":"142321694","uname":">欧拉的费米子","avatar":"http://i2.hdslb.com/bfs/face/e3f846332622491819f389181ba33eccae1eb1dd.jpg","coverUrl":"http://i2.hdslb.com/bfs/archive/2387c7e2efb9bbbb8f8f84094c095f2486735c6a.jpg","title":"4.图册与相容性、微分同胚Diffeomorphism、标
量场、闭集、连通性","duration":3231,"groupTitle":"微分几何入门与广义相对论-梁灿>彬老师（全集）
高清修复1080p","groupCoverUrl":"http://i2.hdslb.com/bfs/archive/2387c7e2efb9bbbb8f8f84094c095f2486735c6a.jpg","danmaku":1648,"view":106781,"pubdate":1645785509,"vt":0,"status":"completed","active":true,"loaded":true,"qn":80,"allowHEVC":false,"createTime":1710406051160,"coverPath":"/Users/stonego/Movies/bilibili/516644182/image.jpg","groupCoverPath":"/Users/stonego/Movies/bilibili/516644182/group.jpg","updateTime":1710406152756,"totalSize":362368975,"loadedSize":362368975,"progress":100,"speed":0,"completionTime":1710406152715,"reportedSize":362368975}
*/

int
get_info(const char* line, char* videoid, char* itemid, char* title, int* part)
{
  const char* video_key = "\"groupId\":\"";
  const size_t len_vk = strlen(video_key);
  const char* item_key = "\"itemId\":";
  const size_t len_ik = strlen(item_key);
  const char* title_key = "\"title\":\"";
  const size_t len_tk = strlen(title_key);
  const char* p_key = "\"p\":";
  const size_t len_pk = strlen(p_key);

  char end = '\"';

  int amount = 0;
  char* ptr = strstr(line, video_key);
  if (ptr) {
    ptr += len_vk;
    char* e = strchr(ptr, end);
    if (e) {
      *e = 0;
      strcpy(videoid, ptr);
      *e = end;
      ++amount;
    }
  }

  end = ',';
  ptr = strstr(line, item_key);
  if (ptr) {
    ptr += len_ik;
    char* e = strchr(ptr, end);
    if (e) {
      *e = 0;
      strcpy(itemid, ptr);
      *e = end;
      ++amount;
    }
  }

  end = '\"';
  ptr = strstr(line, title_key);
  if (ptr) {
    ptr += len_tk;
    char* e = strchr(ptr, end);
    if (e) {
      *e = 0;
      strcpy(title, ptr);
      *e = end;
      ++amount;
    }
  }

  end = ',';
  ptr = strstr(line, p_key);
  if (ptr) {
    ptr += len_pk;
    char* e = strchr(ptr, end);
    if (e) {
      *e = 0;
      *part = atoi(ptr);
      *e = end;
      ++amount;
    }
  }

  return (amount == 4) ? 0 : -1;
}

char buf[BUFSIZ];
size_t n = 0;

int
convert(const char* src, const char* dst)
{
  FILE* f1 = fopen(src, "rb");
  FILE* f2 = fopen(dst, "wb");

  buf[2] = buf[1] = buf[0] = 0;
  fwrite(buf, 1, 3, f2);
  buf[0] = ' ';
  fwrite(buf, 1, 1, f2);

  fseek(f1, 9 + 4, SEEK_SET);
  int n = fread(buf, 1, 12, f1);
  if (n < 0) {
    fclose(f1);
    fclose(f2);
    perror("fread error: ");
    return (-1);
  }
  if (fwrite(buf, 1, 12, f2) < 0) {
    fclose(f1);
    fclose(f2);
    perror("fwrite drror: ");
    return (-2);
  }

  fseek(f1, 4, SEEK_CUR);

  for (;;) {
    n = fread(buf, 1, BUFSIZ, f1);
    if (n > 0)
      fwrite(buf, 1, n, f2);
    if (n < BUFSIZ)
      break;
  }

  fclose(f2);
  fclose(f1);

  return (0);
}

int
convert_main(const char* m4s1, const char* m4s2)
{
  char buf[BUFSIZ];

  FILE* fp = fopen(".videoInfo", "r");
  if (!fp) {
    printf("Can not open info file\n");
    return -3;
  }

  if (!fgets(buf, BUFSIZ, fp)) {
    perror("Error fgets: ");
  }
  fclose(fp);

  char video[32];
  char item[32];
  char title[1024];
  int part = 0;

  if (get_info(buf, video, item, title, &part) < 0)
    return -2;

  char* t1 = "tmp1";
  char* t2 = "tmp2";

  printf("%d - %s %s %s\n", part, video, item, title);

  remove(t1);
  remove(t2);

  convert(m4s1, t1);
  convert(m4s2, t2);

  char mp4_file[2048], out_file[4096];
  snprintf(mp4_file, 2048, "%d-%s.mp4", part, title);
  snprintf(
    buf, BUFSIZ, "ffmpeg -i %s -i %s -codec copy \"%s\"", t1, t2, mp4_file);

  printf("%s\n", buf);

  int n = system(buf);
  if (n < 0) {
    perror("Syste call ffmpeg: ");
  }
  remove(t1);
  remove(t2);

  struct stat st_1, st_2, st_mp4;
  stat(m4s1, &st_1);
  stat(m4s2, &st_2);
  stat(mp4_file, &st_mp4);

  if (st_mp4.st_size - st_1.st_size - st_2.st_size > 0) {
    n = system("rm -f *.m4s dm* view");
    if (n < 0) {
      perror("system call rm");
    }

    snprintf(out_file, 4096, "../%s", video);
    if (stat(out_file, &st_1) != 0) {
      if (errno == 2) {
        mkdir(out_file, 0755);
      }
    }

    snprintf(out_file, 4096, "../%s/%s", video, mp4_file);
    rename(mp4_file, out_file);
  }

  return (0);
}

int convert_single_file(const char* filepath) {
  char outfile[1024];
  snprintf(outfile, 1024, "tmp_%ld", time(0));
  printf("output file is %s\n", outfile);
  return convert(filepath, outfile);
}

int main(int argc, char** argv) {
  if (argc == 2) {
    return convert_single_file(argv[1]);
  } else if (argc == 3) {
    return convert_main(argv[1], argv[2]);
  } else {
    printf("Usage: %s <m4s file1> <m4sfile2> for convert 2 m4s file of bilibili in to one mp4 file\n", argv[0]);
    printf("Usage: %s <m4s file1> for convert one m4s file of bilibili in to a template file with timestamp\n", argv[0]);
  }
  return (0);
}
